#include <stdio.h>
#include <stdlib.h>
#include "List.h"

ListPtr createList()
{
    ListPtr list;
    list = (ListPtr) malloc(sizeof(List));
    list->size = 0;
    list->head = NULL;
    list->tail = NULL;
    return list;
}

void freeList(const ListPtr L)
{
    if(L->head == NULL && L->tail == NULL){
       free(L);
       return;
    }
    NodePtr temp = L->head; 
    NodePtr nextNode; 
    
    while(temp != NULL){
	nextNode = temp->next;
        freeNode(temp);
	temp = nextNode;
    }
    
    free(L);
   
    return;  
    
}

int getSize(const ListPtr L)
{
  if(L == NULL){
      return 0; 
  } 
  
  return L->size;
}

Boolean isEmpty(const ListPtr L)
{
  if(L->head == NULL && L->tail == NULL){ 
      return 1; 
  }
  
  if(L == NULL){
      return 1; 
  }
  
  return 0; 
}

void addAtFront(ListPtr list, NodePtr node)
{
	if (list == NULL) return;
	if (node == NULL) return;
	list->size++;
	
	node->next = list->head;  
	node->prev = NULL; 
	
	if (list->head == NULL) { 
		list->head = node;
		list->tail = node;
	}
	else { 
	    list->head->prev = node; 
	    list->head = node;  
	}
}

void addAtRear(ListPtr list, NodePtr node)
{
   if (list == NULL) return;
   if (node == NULL) return;
	
	//NodePtr temp = list->head; 
	
	  // if(list->size > 0){
	    
	    // if(list->head == node){
	       // return; 
	    // }
	    
	    // while(temp->next != NULL){
		// if(temp->next == node){
		  // return;
		// }
		// temp = temp->next;
	    // }
	  // }

   list->size++; 
   
   node->prev = list->tail; 
   
   node->next = NULL; 
   
   if (list->head == NULL) { 
	list->head = node;
	list->tail = node;
   }
     else { 
	list->tail->next = node; 
	list->tail = node;  
     }
}

NodePtr removeFront(ListPtr list)
{
    if (list == NULL)
   return NULL;
     
   
   if(list->size < 1){
      return NULL;
   }
   NodePtr temp; 
   
   if(list->size == 1){
	  temp = list->head;
      list->head = NULL; 
      list->tail = NULL; 
      list->size--; 
      return temp; 
   } 
   
   temp = list->head;
   list->head = list->head->next; 
   list->head->prev = NULL; 
   
   list->size--;
	
	temp->prev = NULL;
	temp->next = NULL;
   
   return temp;   
}

NodePtr removeRear(ListPtr list)
{
  if (list == NULL) return NULL;
   
   if(list->size < 1){
      return NULL;
   }
   NodePtr temp;
   
   if(list->size == 1){
    temp = list->tail;
      list->head = NULL; 
      list->tail = NULL; 
      list->size--; 
      return temp; 
   }
   
   temp = list->tail;
   list->tail = list->tail->prev; 
   list->tail->next = NULL; 
   
   list->size--;
	
	temp->prev = NULL;
	temp->next = NULL;
   
   return temp;   
}

NodePtr removeNode(ListPtr list, NodePtr node)
{
  
   if (list == NULL) return NULL;
   if (node == NULL) return NULL;
  
  if(list->head == node){
     NodePtr removed = removeFront(list);
     return removed; 
  }
  if(list->tail == node){
      NodePtr removed = removeRear(list);
      return removed; 
  }
  
  NodePtr temp = list->head; 

  if (node -> next != NULL)
  node ->next -> prev = node -> prev;
  
  if(node->prev !=NULL)
  node->prev->next = node-> next;

  node-> next = NULL;
  node-> prev = NULL;
  
  list->size--;
  
  return node; 
}

NodePtr search(const ListPtr list, const int key)
{ 
  return NULL;
}

void reverseList(ListPtr L)
{
   if (L == NULL) return;
  
  NodePtr head = L->head; 
  NodePtr t; 
 
    while(1)
    {
       t = head->prev; 
       head->prev = head->next; 
       head->next = t; 
      
       if(head->prev != NULL){ 
          head = head->prev; 
       }
       else{ 
	 break;
       }
    }
    L->tail = L->head;
    L->head = head;
}

void printList(const ListPtr list)
{
	NodePtr temp = L->head; //Create a temporary variable holding the address of the head node of the list
    int i;
    
    printf("\n");
    
    for(i = 1; i <= L->size; i++){
        printf("%s (next=%p) (prev=%p)\n",toString(temp->data), temp->next, temp->prev); 
        temp = temp->next; 
    }
    
    printf("\n");
}


 